<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/logo.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/logo.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/logo.png">
  <link rel="mask-icon" href="/images/logo.png" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"gitee.com","root":"/","scheme":"Pisces","version":"7.7.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"./public/search.xml"};
  </script>

  <meta name="description" content="click look more">
<meta property="og:type" content="article">
<meta property="og:title" content="Vue+ElementUI最佳实践">
<meta property="og:url" content="https://gitee.com/mamba666/mamba666.git/2020/07/24/Vue+ElementUI%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/index.html">
<meta property="og:site_name" content="共你云雨">
<meta property="og:description" content="click look more">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2020-07-24T08:54:09.879Z">
<meta property="article:modified_time" content="2020-08-17T23:44:56.092Z">
<meta property="article:author" content="Edison">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://gitee.com/mamba666/mamba666.git/2020/07/24/Vue+ElementUI%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true
  };
</script>

  <title>Vue+ElementUI最佳实践 | 共你云雨</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>
	<a href="https://github.com/mamba666" target="_blank" rel="noopener" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">共你云雨</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://gitee.com/mamba666/mamba666.git/2020/07/24/Vue+ElementUI%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Edison">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="共你云雨">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Vue+ElementUI最佳实践
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-07-24 16:54:09" itemprop="dateCreated datePublished" datetime="2020-07-24T16:54:09+08:00">2020-07-24</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-08-18 07:44:56" itemprop="dateModified" datetime="2020-08-18T07:44:56+08:00">2020-08-18</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/" itemprop="url" rel="index"><span itemprop="name">最佳实践</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p>click look more</p>
<a id="more"></a>

<h1 id="项目的初始化"><a href="#项目的初始化" class="headerlink" title="项目的初始化"></a>项目的初始化</h1><ol>
<li>安装vue的脚手架工具，具体见vue文档</li>
<li>通过ui的形式创建一个项目<code>vue ui</code></li>
<li>elementUI</li>
</ol>
<ul>
<li>安装<code>npm install element-ui -S</code></li>
<li>按需引入elementUI<code>npm install babel-plugin-component -D</code></li>
<li>引入element样式<code>import &#39;element-ui/lib/theme-chalk/index.css&#39;</code></li>
<li>修改babel.config.js<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  presets: [</span><br><span class="line">    <span class="string">'@vue/cli-plugin-babel/preset'</span></span><br><span class="line">  ],</span><br><span class="line">  plugins: [</span><br><span class="line">    [</span><br><span class="line">      <span class="string">'component'</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        libraryName: <span class="string">'element-ui'</span>,</span><br><span class="line">        styleLibraryName: <span class="string">'theme-chalk'</span></span><br><span class="line">      &#125;</span><br><span class="line">    ]</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ol start="4">
<li>配置axios<code>npm install axios</code></li>
</ol>
<h1 id="登录退出功能"><a href="#登录退出功能" class="headerlink" title="登录退出功能"></a>登录退出功能</h1><ul>
<li>业务流程</li>
</ul>
<ol>
<li>登录页面输入账号密码</li>
<li>调用后端接口进行验证</li>
<li>通过验证后，根据后台响应跳转到项目的主页</li>
</ol>
<ul>
<li>技术点</li>
</ul>
<ol>
<li>http是没有状态的</li>
<li>通过cookie在<code>客户端</code>记录状态</li>
<li>通过session在<code>服务端</code>记录状态</li>
<li>通过token<code>维持</code>状态</li>
</ol>
<ul>
<li>需要注意的</li>
</ul>
<ol>
<li>如果存在跨域，那么使用token</li>
<li>如果不存在跨域问题，则使用cookie、session</li>
</ol>
<h2 id="token"><a href="#token" class="headerlink" title="token"></a>token</h2><p>token具体是怎么操作的呢？</p>
<ol>
<li>客户端先输入账号密码</li>
<li>如果通过服务端的验证，那么就生成一个token值返回给客户端</li>
<li>客户端在接收到了之后，就会存储下来</li>
<li>在后续，客户端所有的请求都会携带这个token值</li>
<li>服务端会根据这个token值去判断是否通过请求</li>
</ol>
<h2 id="自动重定向路由"><a href="#自动重定向路由" class="headerlink" title="自动重定向路由"></a>自动重定向路由</h2><p>由于登录页需要进入网站就显示，所以需要使用到路由重定向。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 只要访问根路径，就跳转到login页面</span></span><br><span class="line">  &#123;</span><br><span class="line">    path: <span class="string">'/'</span>,</span><br><span class="line">    redirect: <span class="string">'login'</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<h2 id="less"><a href="#less" class="headerlink" title="less"></a>less</h2><p>如果安装插件，less无法正常运行。<code>cnpm install less less-loader -D</code></p>
<h2 id="登录"><a href="#登录" class="headerlink" title="登录"></a>登录</h2><p>在发起登录时，不应该直接请求后端，而是应该在前端实现<code>预验证</code></p>
<p>这里使用validate方法（对整个表单进行校验的方法，参数为一个回调函数。该回调函数会在校验结束后被调用，并传入两个参数：是否校验成功和未通过校验的字段。若不传入回调函数，则会返回一个 promise）</p>
<p>这个方法会返回一个布尔值，这个布尔值是根据之前的rules是否成功来判断的。如果rules通过，返回true，反之返回false。然后根据布尔值去进行下一步的操作</p>
<h2 id="axios的优化"><a href="#axios的优化" class="headerlink" title="axios的优化"></a>axios的优化</h2><ol>
<li>先全局引入axios<code>import axios from &quot;axios&quot;</code></li>
<li>给axios一个基准地址<code>axios.defaults.baseURL = &#39;http://127.0.0.1:8888/api/private/v1/&#39;</code></li>
<li>将axios挂载到vue原型，方便调用<code>Vue.prototype.$http = axios</code></li>
<li>由于axios返回的结果是一个promise对象，所以可以使用async await。<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$refs.loginRef.validate(<span class="keyword">async</span> valid =&gt; &#123;</span><br><span class="line">	<span class="keyword">if</span> (valid) &#123;</span><br><span class="line">		<span class="keyword">const</span> result = <span class="keyword">await</span> <span class="keyword">this</span>.$http.post(<span class="string">'login'</span>, <span class="keyword">this</span>.form)</span><br><span class="line">		<span class="built_in">console</span>.log(result)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li>
<li>最后result返回的是axios封装好了的一个对象，但是我们只需要后端返回的data对象，所以可以使用解构赋值<code>const {data:res} = await this.$http.post(&#39;login&#39;, this.form)</code>。意思是将await出来的数据里面的data赋值给res。</li>
</ol>
<h2 id="弹框提示"><a href="#弹框提示" class="headerlink" title="弹框提示"></a>弹框提示</h2><p>message组件有一点不同，需要全局挂载，类似于之前的axios,在导入组件之后，写如下代码：<br><code>Vue.prototype.$message=Message</code></p>
<h2 id="登录成功之后"><a href="#登录成功之后" class="headerlink" title="登录成功之后"></a>登录成功之后</h2><p>技术点：</p>
<ol>
<li>将登录成功之后的token，保存在客户端的sessionStorage中</li>
</ol>
<ul>
<li>项目中所有其他的接口，都必须在登录成功之后才能访问</li>
<li>token只应该在当前的网站打开期间生效，所以保存在sessionStorage中</li>
<li>localStorage是长久的存储机制，而sessionStorage是会话其间生效的机制</li>
</ul>
<ol start="2">
<li>通过编程式导航，跳转到后台的主页 /home</li>
<li>代码如下</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.sessionStorage.setItem(<span class="string">'token'</span>, res.data.token)</span><br><span class="line"><span class="keyword">this</span>.$router.push(<span class="string">'/home'</span>)</span><br></pre></td></tr></table></figure>

<h2 id="路由导航守卫"><a href="#路由导航守卫" class="headerlink" title="路由导航守卫"></a>路由导航守卫</h2><p>通过路由导航守卫控制页面的访问权限</p>
<p>需求：<code>由于所有接口都需要登录，所以访问任何页面如果没有登录，那么都是没有权限的。如果没有权限，那么一旦访问需要权限的页面，就自动跳转到登录页</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//to:将要访问  from:从哪儿来   next:放行函数</span></span><br><span class="line"><span class="comment">//为路由对象添加beforeEach导航守卫</span></span><br><span class="line">router.beforeEach(<span class="function">(<span class="params">to,<span class="keyword">from</span>,next</span>)=&gt;</span>&#123;</span><br><span class="line">	<span class="comment">//如果访问首登录页，直接放行</span></span><br><span class="line">	<span class="keyword">if</span>(to.path===<span class="string">"/login"</span>) <span class="keyword">return</span> next()</span><br><span class="line">	<span class="comment">//从sessionStorage中获取token值</span></span><br><span class="line">	<span class="keyword">const</span> tokenStr=<span class="built_in">window</span>.sessionStorage.getItem(<span class="string">"token"</span>)</span><br><span class="line">	<span class="comment">//如果没有token，则强制跳转到登录页</span></span><br><span class="line">	<span class="keyword">if</span>(!tokenStr) <span class="keyword">return</span> next(<span class="string">"/login"</span>)</span><br><span class="line">	next()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="退出登录"><a href="#退出登录" class="headerlink" title="退出登录"></a>退出登录</h2><p>只需要销毁token即可</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//清空token</span></span><br><span class="line"><span class="built_in">window</span>.sessionStorage.clear()</span><br><span class="line"><span class="comment">//跳转登录页</span></span><br><span class="line"><span class="keyword">this</span>.$router.push(<span class="string">"/login"</span>)</span><br></pre></td></tr></table></figure>

<h2 id="elementui遇到的坑"><a href="#elementui遇到的坑" class="headerlink" title="elementui遇到的坑"></a>elementui遇到的坑</h2><ul>
<li>让输入框实现密码的效果，即小圆点。在input中输入<code>type=&quot;password&quot;</code></li>
<li>如果要做表单输入验证，即添加rules，那么rules的名字一定要和v-model绑定的数据名一样，不然会发生一个bug。</li>
<li>重置按钮的使用。</li>
</ul>
<ol>
<li>使用resetFields方法（对整个表单进行重置，将所有字段值重置为初始值并移除校验结果）</li>
<li>在按钮上绑定一个事件，但是要注意，这个事件触发时，this指向整个组件</li>
<li>所以要使用<code>this.$refs.自己定义的表单的ref</code>去获取到表单的元素</li>
<li>在调用resetFields方法即可</li>
</ol>
<h1 id="主页"><a href="#主页" class="headerlink" title="主页"></a>主页</h1><h2 id="布局"><a href="#布局" class="headerlink" title="布局"></a>布局</h2><p>使用Container组件，需要引入4个小组件：Container、Header、Aside、Main</p>
<h2 id="头部的布局"><a href="#头部的布局" class="headerlink" title="头部的布局"></a>头部的布局</h2><ul>
<li>logo部分使用img标签<code>&lt;img src=&quot;../assets/logo.png&quot; alt /&gt;</code></li>
<li>垂直居中flex布局就完事了</li>
</ul>
<h2 id="菜单栏"><a href="#菜单栏" class="headerlink" title="菜单栏"></a>菜单栏</h2><ul>
<li>菜单为二级菜单，可以折叠</li>
<li>使用了NavMenu组件，需要引入3个小组件：Menu、SubMenu、MenuItem</li>
</ul>
<h2 id="菜单栏调用API接口"><a href="#菜单栏调用API接口" class="headerlink" title="菜单栏调用API接口"></a>菜单栏调用API接口</h2><ul>
<li>有一点需要注意，在这种非登录页的API都需要权限，所以这里调用API的时候都需要使用到token值。<code>做法：在请求头中使用Authorization字段提供token令牌</code></li>
</ul>
<h2 id="为axios添加拦截器"><a href="#为axios添加拦截器" class="headerlink" title="为axios添加拦截器"></a>为axios添加拦截器</h2><p>接上一步，因为需要使用到token，所以肯定在请求之前要有一个拦截，保证其拥有获取数据的权限。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//axios拦截器</span></span><br><span class="line">axios.interceptors.request.use(<span class="function"><span class="params">config</span>=&gt;</span>&#123;</span><br><span class="line">	<span class="comment">//为请求头对象添加token验证的Authorization字段</span></span><br><span class="line">	config.headers.Authorization=<span class="built_in">window</span>.sessionStorage.getItem(<span class="string">"token"</span>)</span><br><span class="line">	<span class="keyword">return</span> config</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="解决菜单栏下拉时全部展开的问题"><a href="#解决菜单栏下拉时全部展开的问题" class="headerlink" title="解决菜单栏下拉时全部展开的问题"></a>解决菜单栏下拉时全部展开的问题</h2><p>在 el-submenu 组件中，有一个 index 值是一个唯一标识符。由于 v-for 渲染出来的每一个 index 都是一样的，所以需要动态绑定一个唯一值。由于后端获取的数据一般都有一个 id 值，所以可以使用这个 id 值</p>
<p>由于 index 只接收字符串，而 item.id 是一个数值，所以最简单的办法就是在后面添加一个空的字符串区转换数据类型</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-submenu</span> <span class="attr">v-for</span>=<span class="string">"item in menuList"</span> <span class="attr">:key</span>=<span class="string">"item.id"</span> <span class="attr">:index</span>=<span class="string">"item.id+''"</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="渲染二级菜单"><a href="#渲染二级菜单" class="headerlink" title="渲染二级菜单"></a>渲染二级菜单</h2><p>一级菜单就是常规操作，但是二级菜单不一样，它所依赖的对象不是 data 中定义的。而是一级菜单</p>
<p>比如一级菜单<code>item in menuList</code>；二级菜单就是<code>subItem in item.children</code></p>
<h2 id="自定义icon"><a href="#自定义icon" class="headerlink" title="自定义icon"></a>自定义icon</h2><p>由于菜单是循环渲染出来的，而icon图标又是死的，所以不能直接改动icon的样式，不然所有的一级菜单icon都是一个样子。所以需要自定义图标。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在data中自定义一个icons的对象，里面包含一级菜单需要用到的icon</span></span><br><span class="line">iconsObj: &#123;</span><br><span class="line">	<span class="comment">// 每个菜单项都有一个唯一的id值</span></span><br><span class="line">	<span class="comment">// 所以可以使用id作为键，icon作为值</span></span><br><span class="line">	<span class="comment">// 需要注意，前面的键，是后端返回的一级菜单数据的id值</span></span><br><span class="line">	<span class="number">125</span>: <span class="string">'el-icon-s-custom'</span>,</span><br><span class="line">	<span class="number">103</span>: <span class="string">'el-icon-box'</span>,</span><br><span class="line">	<span class="number">101</span>: <span class="string">'el-icon-shopping-bag-1'</span>,</span><br><span class="line">	<span class="number">102</span>: <span class="string">'el-icon-s-order'</span>,</span><br><span class="line">	<span class="number">145</span>: <span class="string">'el-icon-s-marketing'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在定义好了icons的数据之后怎么使用呢？这就需要用到动态绑定。<br>原先的代码为：<code>&lt;i class=&quot;el-icon-xxx&quot;&gt;&lt;/i&gt;</code>。<br>修改为：<code>&lt;i :class=&quot;iconsObj[item.id]&quot;&gt;&lt;/i&gt;</code>这里的class前面加上冒号，意思是其现在为一个动态绑定的数据，然后直接使用上面定义好的iconsObj,通过[]形式取到icon的值。</p>
<h2 id="UI坑"><a href="#UI坑" class="headerlink" title="UI坑"></a>UI坑</h2><ul>
<li>在elementUI中，很多组件都有一些属性，比如说Menu的collapse等，他们都是布尔值，如果直接在标签中写<code>collapse=&quot;false&quot;</code>，就会报错，因为此时false只是一个字符串，要想使它生效，就要在前面加一个冒号，表示为动态绑定值<code>:collapse=&quot;false&quot;</code></li>
<li>关于动态绑定值在菜单栏的折叠与展开也用到了，因为 aside 有一个写死的宽度，但是这个宽度要根据是否折叠来判断宽度为多少。比如折叠了就64px，反之200px。代码：<code>&lt;el-aside :width=&quot;isCollapse?&#39;64px&#39;:&#39;200px&#39;&quot;&gt;</code></li>
</ul>
<h2 id="嵌套组件"><a href="#嵌套组件" class="headerlink" title="嵌套组件"></a>嵌套组件</h2><p>有一个需求是，访问home页，在没有点击侧边栏的时候就直接跳转到welcome路由，然后会在main区域显示一个welcome。</p>
<p>首先定义一个children子路由，然后通过redirect重定向到welcome路由，就会显示welcome组件，但是，welcome只是一个占位符，所以main中就显示了welcome的组件内容。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">   path: <span class="string">'/home'</span>,</span><br><span class="line">   component: Home,</span><br><span class="line">   redirect: <span class="string">'/welcome'</span>,</span><br><span class="line">   children: [</span><br><span class="line">     &#123;</span><br><span class="line">       path: <span class="string">'/welcome'</span>,</span><br><span class="line">       component: Welcome</span><br><span class="line">     &#125;</span><br><span class="line">   ]</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h2 id="菜单栏的路由链接"><a href="#菜单栏的路由链接" class="headerlink" title="菜单栏的路由链接"></a>菜单栏的路由链接</h2><p>需求是点击菜单栏的选项，main区域就会显示当前菜单所对应的组件内容。在以前就路由导航和link区跳转路由，但是由于使用了elementUI，有一个简单的方法。</p>
<p>router：<code>是否使用 vue-router 的模式，启用该模式会在激活导航时以 index 作为 path 进行路由跳转</code></p>
<p>既然开启了vue-router模式，那么跳转的路由就会是一个id值，为一个数值。但是路由不能这样，所以，要把二级菜单的index值替换成后端返回的path值。<code>:index=&quot;&#39;/&#39;+subItem.path+&#39;&#39;&quot;</code></p>
<h1 id="用户列表"><a href="#用户列表" class="headerlink" title="用户列表"></a>用户列表</h1><p>就是一个展示用户列表的组件。并且显示在main区域。</p>
<p>页面：</p>
<ol>
<li>顶部是面包屑导航</li>
<li>主体内容用卡片包裹起来</li>
<li>卡片中又有搜索框，按钮，表格展示的用户列表、跳转页面栏</li>
</ol>
<p>使用到的组件：</p>
<ul>
<li>面包屑导航：Breadcrumb、BreadcrumbItem</li>
<li>搜索框、按钮：Input、Button</li>
<li>表格：Table、TableColumn</li>
<li>文字提示：Tooltip</li>
<li>分页：Pagination</li>
<li>对话框：Dialog</li>
</ul>
<h2 id="根据路由展示组件"><a href="#根据路由展示组件" class="headerlink" title="根据路由展示组件"></a>根据路由展示组件</h2><p>之前已经嵌套了welcome的组件，现在还需要继续增加子菜单的路由，直接在children中写就行。之后其他的组件以此类推。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">   path: <span class="string">'/home'</span>,</span><br><span class="line">   component: Home,</span><br><span class="line">   redirect: <span class="string">'/welcome'</span>,</span><br><span class="line">   children: [</span><br><span class="line">     &#123;</span><br><span class="line">       path: <span class="string">'/welcome'</span>,</span><br><span class="line">       component: Welcome</span><br><span class="line">     &#125;,</span><br><span class="line">     &#123;</span><br><span class="line">       path: <span class="string">'/users'</span>,</span><br><span class="line">       component: Users</span><br><span class="line">     &#125;</span><br><span class="line">   ]</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h2 id="二级菜单不高亮的bug"><a href="#二级菜单不高亮的bug" class="headerlink" title="二级菜单不高亮的bug"></a>二级菜单不高亮的bug</h2><p>在前面的做完后，发现点击二级菜单没有高亮了。</p>
<p>使用default-active解决。default-active:<code>当前激活菜单的 index</code></p>
<p>解决思路：</p>
<ol>
<li>首先给二级菜单绑定事件，让其被点击的时候，在sessionStorage中存储下这个路由的值。</li>
<li>由于default-active是根据当前激活菜单的index值去判断是否高亮的。所以，将点击事件的参数写为二级菜单的index值。</li>
<li>将index值传入函数后，就通过sessionStorage去存储这个index值。同时将data中定义好的activePath赋值<code>this.activePath=activePath</code>。由于menu中的default-active已经动态绑定了activePath的值，所以可以被高亮。</li>
<li>接着在钩子函数created中将activePath的值从sessionStorage中取出来<code>this.activePath = window.sessionStorage.getItem(&#39;activePath&#39;)</code>。这时即使刷新了页面，还是会保持高亮。</li>
</ol>
<h2 id="样式的位置"><a href="#样式的位置" class="headerlink" title="样式的位置"></a>样式的位置</h2><ul>
<li>如果组件要覆盖自己的默认样式，就要写到全局样式文件中。</li>
<li>在重置box-shadow时，遇到了不生效的问题，此时可以使用!important<code>box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) !important;</code></li>
</ul>
<h2 id="get请求带参数写法"><a href="#get请求带参数写法" class="headerlink" title="get请求带参数写法"></a>get请求带参数写法</h2><p>api接口规定了一个get请求，必须携带三个参数，之前都是没有参数的。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 常规的async await</span></span><br><span class="line">   <span class="keyword">async</span> getUserList() &#123;</span><br><span class="line">    <span class="comment">//不同的是，这次类似于post请求，在接口后带了一个对象。</span></span><br><span class="line">     <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="keyword">this</span>.$http.get(<span class="string">'users'</span>, &#123;</span><br><span class="line">     	<span class="comment">//params的值就是this.queryInfo</span></span><br><span class="line">     	<span class="comment">//queryInfo定义在data数据中</span></span><br><span class="line">       params: <span class="keyword">this</span>.queryInfo</span><br><span class="line">     &#125;)</span><br><span class="line">     <span class="built_in">console</span>.log(res)</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<h2 id="数据的改造"><a href="#数据的改造" class="headerlink" title="数据的改造"></a>数据的改造</h2><p>表格中需要渲染的状态是一个布尔值，但是要渲染成开关的样式，所以就涉及到了数据的改造。</p>
<ul>
<li>由于状态的数据是每一行都存在的，所以，只要获取到这一行的数据，就可以找到状态。</li>
<li>这里需要使用到<code>作用域插槽</code></li>
<li>通过scope.row就可以获取到当前行的所有数据。</li>
<li>然后将scoped绑定到switch组件上就可。</li>
<li>在指定了作用域插槽后，会将prop覆盖掉</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">"状态"</span> <span class="attr">prop</span>=<span class="string">"mg_state"</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">template</span> <span class="attr">v-slot</span>=<span class="string">"scope"</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">el-switch</span> <span class="attr">v-model</span>=<span class="string">"scope.row.mg_state"</span>&gt;</span><span class="tag">&lt;/<span class="name">el-switch</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="鼠标悬浮的提示框"><a href="#鼠标悬浮的提示框" class="headerlink" title="鼠标悬浮的提示框"></a>鼠标悬浮的提示框</h2><p>有一个需求是鼠标放上去就提示文字信息，因为有一些按钮不太方便理解。</p>
<p>这里使用tooltip的组件即可。但是有一个小问题，如果文字提示的方向是top，那么鼠标放上去时弹出的文字提示会覆盖掉上面的按钮。所以需要自动隐藏。</p>
<p>解决方案：<code>使用enterable：鼠标是否可以进入到tooltip中</code>。这里也要注意enterable也需要动态绑定，因为是布尔值。<code>:enterable=&quot;false&quot;</code></p>
<h2 id="使用tooltip"><a href="#使用tooltip" class="headerlink" title="使用tooltip"></a>使用tooltip</h2><p>tooltip是分页器组件，在使用是，点击页码尺寸和页码都会触发事件，这时在事件中就可以将之前定义好的接口所需要的函数重新赋值，然后再次调用接口请求数据即可。千万不要只重新赋值，不然页面不会重新渲染。</p>
<h2 id="接口中有参数的解决方案"><a href="#接口中有参数的解决方案" class="headerlink" title="接口中有参数的解决方案"></a>接口中有参数的解决方案</h2><p>现在有一个接口：<code>users/:uId/state/:type</code>。<br>一般为了方便，都会使用模板字符串改写为：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 监听用户状态发生的改变</span></span><br><span class="line"><span class="keyword">async</span> userStatechange(userInfo) &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="keyword">this</span>.$http.put(</span><br><span class="line">    <span class="string">`users/<span class="subst">$&#123;userInfo.id&#125;</span>/state/<span class="subst">$&#123;userInfo.mg_state&#125;</span>`</span></span><br><span class="line">  )</span><br><span class="line">  <span class="keyword">if</span> (res.meta.status !== <span class="number">200</span>) &#123;</span><br><span class="line">    <span class="comment">// 虽然这里更新失败，但是前端的页面已经更新成功了，所以还要将状态取反</span></span><br><span class="line">    userInfo.mg_state = !userInfo.mg_state</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.$message.error(<span class="string">'更新用户状态失败'</span>)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">this</span>.$message.success(<span class="string">'更新成功'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="搜索框的清空"><a href="#搜索框的清空" class="headerlink" title="搜索框的清空"></a>搜索框的清空</h2><p>input组件提供了一个属性：<code>clearable:在输入文本后，后面会出现一个按钮，点击后就可以清空输入的文本</code>。</p>
<p>但是清空后，并没有重新渲染页面，还是在之前的页面。所以还提供了一个事件：<code>clear:再点击清空按钮时，立即触发</code></p>
<p>所以可以这么写:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-input</span> @<span class="attr">clear</span>=<span class="string">"clear"</span> <span class="attr">v-model</span>=<span class="string">"queryInfo.query"</span> <span class="attr">clearable</span> <span class="attr">placeholder</span>=<span class="string">"请输入内容"</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 清空搜索框，并且重新请求数据</span></span><br><span class="line">clear() &#123;</span><br><span class="line">	<span class="keyword">this</span>.getUserList()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="自定义校验规则"><a href="#自定义校验规则" class="headerlink" title="自定义校验规则"></a>自定义校验规则</h2><p>在添加用户的时候，需要输入邮箱和手机号，由于这两个比较特殊，所以需要用到自定义校验规则</p>
<ul>
<li>首先定义两个自定义的校验规则。使用test方法去测试是否正确</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 自定义校验规则</span></span><br><span class="line"><span class="keyword">const</span> checkEmail = <span class="function">(<span class="params">rule, value, callback</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> regEmail = <span class="regexp">/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/</span></span><br><span class="line">  <span class="keyword">if</span> (regEmail.test(value)) &#123;</span><br><span class="line">    <span class="keyword">return</span> callback()</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    callback(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'请输入合法的邮箱地址'</span>))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> checkMobile = <span class="function">(<span class="params">rule, value, callback</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> regMobile = <span class="regexp">/^(0|86|17951)?(13[0-9]|15[0123456789]|17[678]|18(0-9)|14[57])[0-9]&#123;8&#125;$/</span></span><br><span class="line">  <span class="keyword">if</span> (regMobile.test(value)) &#123;</span><br><span class="line">    <span class="keyword">return</span> callback()</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    callback(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'请输入合法的手机号'</span>))</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>然后添加到rules的规则中。使用validator指定之前定义好的校验的规则</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">email: [</span><br><span class="line">    &#123; <span class="attr">required</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">'请输入邮箱'</span>, <span class="attr">trigger</span>: <span class="string">'blur'</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">validator</span>: checkEmail, <span class="attr">trigger</span>: <span class="string">'blur'</span> &#125;</span><br><span class="line">],</span><br><span class="line">mobile: [</span><br><span class="line">    &#123; <span class="attr">required</span>: <span class="literal">true</span>, <span class="attr">message</span>: <span class="string">'请输入手机号'</span>, <span class="attr">trigger</span>: <span class="string">'blur'</span> &#125;,</span><br><span class="line">    &#123; <span class="attr">validator</span>: checkMobile, <span class="attr">trigger</span>: <span class="string">'blur'</span> &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<h2 id="添加用户之后的bug"><a href="#添加用户之后的bug" class="headerlink" title="添加用户之后的bug"></a>添加用户之后的bug</h2><p>在添加用户后，不管取消还是确定，再次打开的时候，表单里还是上一次填的数据，所以要进行一次清空操作。</p>
<ul>
<li>首先监听对话框的关闭事件</li>
<li>在关闭事件中重置表单</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 首先监听到表单的close事件，然后绑定一个函数addDialogClosed</span></span><br><span class="line"><span class="comment">// 清空添加用户的数据</span></span><br><span class="line">addDialogClosed() &#123;</span><br><span class="line">	<span class="comment">//addFormRef是表单的ref，然后调用resetFields</span></span><br><span class="line">	<span class="keyword">this</span>.$refs.addFormRef.resetFields()</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="修改用户数据"><a href="#修改用户数据" class="headerlink" title="修改用户数据"></a>修改用户数据</h1><ul>
<li>首先点击修改的按钮，然后弹出来一个dialog对话框组件。</li>
<li>然后对话框里面有三个输入框，分别为用户名、邮箱、手机号。</li>
<li>用户名：用户名不可修改，可在input组件中使用disabled属性将其设置为不可修改</li>
<li>三个输入框的内容需要通过调用API去查询，然后渲染出来</li>
<li>但是需要id作为参数，因为要通过id去查询。</li>
<li>由于修改的按钮在作用域插槽中，所以可以通过<code>scope.row.id</code>作为参数传入事件绑定的函数</li>
<li>然后就可以查询了，并且将查询的值赋值给data中的editForm</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 展示修改用户信息</span></span><br><span class="line"><span class="keyword">async</span> showEditDialog(id) &#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="keyword">this</span>.$http.get(<span class="string">'users/'</span> + id)</span><br><span class="line">  <span class="keyword">if</span> (res.meta.status !== <span class="number">200</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.$message.error(<span class="string">'查询用户信息失败'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">this</span>.editForm = res.data</span><br><span class="line">  <span class="keyword">this</span>.editDialogVisible = <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>此时弹出的对话框就有了初始的数据，然后在开始填写</li>
<li>在点击确定的时候，就要调用API去修改，因为这里也是向服务器修改数据，所以也需要一个预验证去校验是否正确。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 提交修改</span></span><br><span class="line">    editUser() &#123;</span><br><span class="line">      <span class="keyword">this</span>.$refs.editFormRef.validate(<span class="keyword">async</span> valid =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (!valid) <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="keyword">this</span>.$http.put(</span><br><span class="line">          <span class="string">'users/'</span> + <span class="keyword">this</span>.editForm.id,</span><br><span class="line">          &#123;</span><br><span class="line">            email: <span class="keyword">this</span>.editForm.email,</span><br><span class="line">            mobile: <span class="keyword">this</span>.editForm.mobile</span><br><span class="line">          &#125;</span><br><span class="line">        )</span><br><span class="line">        <span class="keyword">if</span> (res.meta.status !== <span class="number">200</span>) &#123;</span><br><span class="line">          <span class="built_in">console</span>.log(res.meta.status)</span><br><span class="line">          <span class="keyword">return</span> <span class="keyword">this</span>.$message.error(<span class="string">'修改失败'</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="keyword">this</span>.editDialogVisible = <span class="literal">false</span></span><br><span class="line">          <span class="keyword">this</span>.getUserList()</span><br><span class="line">          <span class="keyword">this</span>.$message.success(<span class="string">'修改成功'</span>)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="put请求，一个必须参数，两个非必须参数"><a href="#put请求，一个必须参数，两个非必须参数" class="headerlink" title="put请求，一个必须参数，两个非必须参数"></a>put请求，一个必须参数，两个非必须参数</h2><p>那么怎么写呢？</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$http.put(<span class="string">'users/'</span>+<span class="string">'必须的参数'</span>,&#123;</span><br><span class="line">	非必须的参数键:非必须参数的值</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h1 id="删除用户数据"><a href="#删除用户数据" class="headerlink" title="删除用户数据"></a>删除用户数据</h1><ul>
<li>点击删除按钮就调用删除的API</li>
<li>但是要注意，删除是敏感操作，所以要在删除前让用户再次确认</li>
<li>这就需要使用到MessageBox弹框组件</li>
<li>在按需引入组件后，还需要挂载到Vue原型上<code>Vue.prototype.confirm=MessageBox.confirm</code></li>
<li><code>this.$confirm</code>返回的是一个promise对象，所以可以使用async await 优化</li>
<li>要注意最后返回的值！</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 删除用户信息</span></span><br><span class="line"><span class="keyword">async</span> deleteUser(id) &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(id)</span><br><span class="line">  <span class="keyword">const</span> confirmResult = <span class="keyword">await</span> <span class="keyword">this</span>.$confirm(</span><br><span class="line">    <span class="string">'此操作将永久用户信息, 是否继续?'</span>,</span><br><span class="line">    <span class="string">'删除用户信息'</span>,</span><br><span class="line">    &#123;</span><br><span class="line">      confirmButtonText: <span class="string">'确定'</span>,</span><br><span class="line">      cancelButtonText: <span class="string">'取消'</span>,</span><br><span class="line">      type: <span class="string">'warning'</span></span><br><span class="line">    &#125;</span><br><span class="line">  ).catch(<span class="function"><span class="params">err</span> =&gt;</span> err)</span><br><span class="line">  <span class="comment">// 确定就返回一个confirm字符串</span></span><br><span class="line">  <span class="comment">// 取消就报错，所以上面加了catch捕获错误</span></span><br><span class="line">  <span class="comment">// 加了catch后返回一个cancel字符串</span></span><br><span class="line">  <span class="comment">// 那么现在就可以使用返回的字符串去判断是否删除信息</span></span><br><span class="line">  <span class="comment">// console.log(confirmResult)</span></span><br><span class="line">  <span class="keyword">if</span> (confirmResult !== <span class="string">'confirm'</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.$message.error(<span class="string">'取消删除'</span>)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="attr">data</span>: res &#125; = <span class="keyword">await</span> <span class="keyword">this</span>.$http.delete(<span class="string">'users/'</span> + id)</span><br><span class="line">    <span class="keyword">if</span> (res.meta.status !== <span class="number">200</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>.$message.error(<span class="string">'删除用户'</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">this</span>.getUserList()</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>.$message.success(<span class="string">'删除成功'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="权限列表"><a href="#权限列表" class="headerlink" title="权限列表"></a>权限列表</h1><ul>
<li>组件：</li>
<li>Tag标签</li>
</ul>
<h2 id="渲染tag标签"><a href="#渲染tag标签" class="headerlink" title="渲染tag标签"></a>渲染tag标签</h2><ul>
<li>首先这里拿到的数据是一个数值，但是要根据数值去选择使用什么样式的tag标签</li>
<li>由于是在table中嵌套了一个tag组件，所以可以使用作用域插槽</li>
<li>然后使用v-show去判断展示什么。</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">"权限等级"</span> <span class="attr">prop</span>=<span class="string">"level"</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">template</span> <span class="attr">v-slot</span>=<span class="string">"scope"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">el-tag</span> <span class="attr">v-if</span>=<span class="string">"scope.row.level==='0'"</span>&gt;</span>一级权限<span class="tag">&lt;/<span class="name">el-tag</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">el-tag</span> <span class="attr">v-if</span>=<span class="string">"scope.row.level==='1'"</span> <span class="attr">type</span>=<span class="string">"success"</span>&gt;</span>二级权限<span class="tag">&lt;/<span class="name">el-tag</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">el-tag</span> <span class="attr">v-if</span>=<span class="string">"scope.row.level==='2'"</span> <span class="attr">type</span>=<span class="string">"warning"</span>&gt;</span>三级权限<span class="tag">&lt;/<span class="name">el-tag</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h1 id="角色列表"><a href="#角色列表" class="headerlink" title="角色列表"></a>角色列表</h1><h2 id="表格展开操作"><a href="#表格展开操作" class="headerlink" title="表格展开操作"></a>表格展开操作</h2><ul>
<li>表格前面不再是index索引，而是一个尖括号，点击后可以展开。<code>type=&quot;expand&quot;</code></li>
<li>展开后显示的是当前角色所拥有的权限。</li>
<li><code>&lt;pre&gt;&lt;/pre&gt;</code>作用是将一坨数据格式化，清晰方便。</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 天秀操作，可展开,具体是角色下的权限 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">type</span>=<span class="string">"expand"</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;<span class="name">template</span> <span class="attr">v-slot</span>=<span class="string">"scope"</span>&gt;</span></span><br><span class="line">			<span class="tag">&lt;<span class="name">pre</span>&gt;</span>&#123;&#123;scope.row&#125;&#125;<span class="tag">&lt;/<span class="name">pre</span>&gt;</span></span><br><span class="line">		<span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="多层数据的提取"><a href="#多层数据的提取" class="headerlink" title="多层数据的提取"></a>多层数据的提取</h2><p>后端经常返回很多层的数据，就是嵌套的数据，那么就需要通过一定的方法将其提取出来。</p>
<p>这里有三层，其实方法和之前主页的二级菜单渲染是一样的。</p>
<h2 id="角色列表展开项的美化"><a href="#角色列表展开项的美化" class="headerlink" title="角色列表展开项的美化"></a>角色列表展开项的美化</h2><ul>
<li>css选择器。以下是两个标签中class的定义。跟以前的class完全不一样。</li>
<li>具体什么意思呢？</li>
</ul>
<ol>
<li>首先，class前面有冒号，所以就是一个动态的值，不是死的数据。</li>
<li>第一个类表示首先添加一个bdbottom的类，然后通过三元表达式去判断（i1为第一层for循环的索引，i2同理）是否成立，然后根据结果调用。</li>
<li>比如第一个class的意思就是索引是否为0，即是否为第一个渲染的元素？是的话就添加一个bdtop的类，不是的话就不操作。<br><code>:class=&quot;[&#39;bdbottom&#39;,i1===0?&#39;bdtop&#39;:&#39;&#39;,&#39;vcenter&#39;]&quot;</code><br><code>:class=&quot;[i2===0?&#39;&#39;:&#39;bdtop&#39;,&#39;vcenter&#39;]&quot;</code></li>
</ol>
<h2 id="标签的删除"><a href="#标签的删除" class="headerlink" title="标签的删除"></a>标签的删除</h2><ul>
<li>为tag标签添加一个属性closeable即可。</li>
<li>同时，tag标签有两个事件：click和close。</li>
</ul>
<p>有一点是在删除之后，权限展开的效果会被自动关闭。那是因为直接请求了重新渲染整个列表，而实际上只需要取到第三级的权限列表然后赋值即可</p>
<h2 id="渲染树形数据结构"><a href="#渲染树形数据结构" class="headerlink" title="渲染树形数据结构"></a>渲染树形数据结构</h2><ul>
<li>在分配权限中，返回的是一个树形的数据结构</li>
<li>要使用到Tree树形控件</li>
</ul>
<p>渲染完成后优化Tree组件：</p>
<ul>
<li>使用show-checkbox可以使数据前面加上复选框。但是选择后只是打了个勾，并没有实际的含义，所以这里用到Tree组件的node-key属性<code>每个树节点用来作为唯一标识的属性，整棵树应该是唯一的</code></li>
<li>使用default-expand-all属性<code>是否默认展开所有节点</code>即可展开树形结构</li>
<li>使用default-checked-keys属性<code>默认勾选的节点的 key 的数组</code>即可勾选已存在的节点。值得注意的是，需要传入id值。那么这个id值怎么获取呢？只需要获取第三级就行，因为一二级都是半选状态，只要三级有，那么一二级也有。所以在获取三级权限数据时，将id添加到数据中</li>
<li>使用递归函数去获取三级节点的id</li>
</ul>
<h1 id="商品分类"><a href="#商品分类" class="headerlink" title="商品分类"></a>商品分类</h1><h2 id="树形table"><a href="#树形table" class="headerlink" title="树形table"></a>树形table</h2><p>官方描述：<code>支持树类型的数据的显示。当 row 中包含 children 字段时，被视为树形数据。渲染树形数据时，必须要指定 row-key。支持子节点数据异步加载。设置 Table 的 lazy 属性为 true 与加载函数 load 。通过指定 row 中的 hasChildren 字段来指定哪些行是包含子节点。children 与 hasChildren 都可以通过 tree-props 配置。</code></p>
<ul>
<li>首先绑定一个数据cateList（从后端获取的）</li>
<li>新增的row-key：从cateList中找到id值（必须）</li>
<li>:tree-props：children就是cateList中的子数据</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-table</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:tree-props</span>=<span class="string">"&#123;children: 'children'&#125;"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">row-key</span>=<span class="string">"cat_id"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">border</span></span></span><br><span class="line"><span class="tag">    <span class="attr">stripe</span></span></span><br><span class="line"><span class="tag">    <span class="attr">:data</span>=<span class="string">"cateList"</span></span></span><br><span class="line"><span class="tag">&gt;</span></span><br></pre></td></tr></table></figure>

<h1 id="上传图片功能"><a href="#上传图片功能" class="headerlink" title="上传图片功能"></a>上传图片功能</h1><ul>
<li>使用了upload组件的图片列表缩略图</li>
<li>action:图片将要上传的地址，写后台的上传图片接口地址</li>
<li>on-preview:点击文件列表中已上传的文件时的钩子</li>
<li>on-remove:文件列表移除文件时的钩子</li>
<li>file-list:上传的文件列表, 例如: [{name: ‘food.jpg’, url: ‘<a href="https://xxx.cdn.com/xxx.jpg&#39;}]" target="_blank" rel="noopener">https://xxx.cdn.com/xxx.jpg&#39;}]</a></li>
<li>list-type:文件列表的类型</li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">el-upload</span></span></span><br><span class="line"><span class="tag">  <span class="attr">action</span>=<span class="string">"https://jsonplaceholder.typicode.com/posts/"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">:on-preview</span>=<span class="string">"handlePreview"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">:on-remove</span>=<span class="string">"handleRemove"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">:file-list</span>=<span class="string">"fileList"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">list-type</span>=<span class="string">"picture"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">el-button</span> <span class="attr">size</span>=<span class="string">"small"</span> <span class="attr">type</span>=<span class="string">"primary"</span>&gt;</span>点击上传<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">slot</span>=<span class="string">"tip"</span> <span class="attr">class</span>=<span class="string">"el-upload__tip"</span>&gt;</span>只能上传jpg/png文件，且不超过500kb<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-upload</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>但是会遇到一个问题，就是这个接口地址只是被actions使用了，但是除了login的接口以外，其他接口都会在请求前有一个拦截，这个拦截器会是通过axios调用的。而这里没有使用axios，所以携带不了token，所以图片并没有上传上去。</p>
<p>这就需要为upload组件手动去绑定headers请求头。</p>
<p>刚好upload组件就有一个属性为headers：<code>设置上传的请求头部</code></p>
<ul>
<li>在upload中绑定一个动态的headers属性<code>:headers=&quot;headerObj&quot;</code></li>
<li>在data中定义一个headerObj数据:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">headerObj: &#123;</span><br><span class="line">	Authorization: <span class="built_in">window</span>.sessionStorage.getItem(<span class="string">'token'</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="图片预览窗口"><a href="#图片预览窗口" class="headerlink" title="图片预览窗口"></a>图片预览窗口</h1><p>在图片上传后，有一个需求就是点击后，图片可以放大预览。</p>
<p>这个操作由on-preview触发，并且这个函数接收一个形参file。这个file打印出来的就是上传的图片的对象属性，包含了name、percentage、row、response等属性。这个response就是后端返回的数据。</p>
<p>然后根据后端返回的路径，找到那个可以显示的路径<code>file.response.data.url</code>。然后将其赋值到新的数据上。在通过dialog组件展示。</p>
<p>但是会遇到图片过大，超出dialog显示区域的bug。只需要给img加上样式即可</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 图片预览 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">el-dialog</span> <span class="attr">title</span>=<span class="string">"图片预览"</span> <span class="attr">:visible.sync</span>=<span class="string">"previewVisible"</span> <span class="attr">width</span>=<span class="string">"50%"</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">img</span> <span class="attr">class</span>=<span class="string">"previewImg"</span> <span class="attr">:src</span>=<span class="string">"preViewPath"</span> <span class="attr">alt</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">el-dialog</span>&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">handlePreview(file) &#123;</span><br><span class="line">    <span class="keyword">this</span>.preViewPath = file.response.data.url</span><br><span class="line">    <span class="keyword">this</span>.previewVisible = <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.previewImg</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="富文本编辑器"><a href="#富文本编辑器" class="headerlink" title="富文本编辑器"></a>富文本编辑器</h1><ul>
<li>先安装插件vue-quill-editor</li>
<li><code>cnpm install vue-quill-editor</code></li>
<li>配置：</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> VueQuillEditor <span class="keyword">from</span> <span class="string">'vue-quill-editor'</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// require styles</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">'quill/dist/quill.core.css'</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">'quill/dist/quill.snow.css'</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">'quill/dist/quill.bubble.css'</span></span><br><span class="line"> </span><br><span class="line">Vue.use(VueQuillEditor, <span class="comment">/* &#123; default global options &#125; */</span>)</span><br></pre></td></tr></table></figure>

<p>然后直接使用<code>&lt;quill-editor&gt;&lt;/quill-editor&gt;</code>即可</p>
<p>更详细的使用方法看官方文档即可。</p>
<h1 id="使用Echarts"><a href="#使用Echarts" class="headerlink" title="使用Echarts"></a>使用Echarts</h1><h2 id="基本的使用"><a href="#基本的使用" class="headerlink" title="基本的使用"></a>基本的使用</h2><ul>
<li>安装插件<code>cnpm install echarts -S</code></li>
<li>由于只有一个页面使用了echarts，所以直接在那个页面导入即可</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;!-- 面包屑导航区域 --&gt;</span><br><span class="line">    &lt;el-breadcrumb separator&#x3D;&quot;&#x2F;&quot;&gt;</span><br><span class="line">      &lt;el-breadcrumb-item :to&#x3D;&quot;&#123; path: &#39;&#x2F;home&#39; &#125;&quot;&gt;首页&lt;&#x2F;el-breadcrumb-item&gt;</span><br><span class="line">      &lt;el-breadcrumb-item&gt;数据统计&lt;&#x2F;el-breadcrumb-item&gt;</span><br><span class="line">      &lt;el-breadcrumb-item&gt;数据报表&lt;&#x2F;el-breadcrumb-item&gt;</span><br><span class="line">    &lt;&#x2F;el-breadcrumb&gt;</span><br><span class="line">    &lt;!-- 卡片 --&gt;</span><br><span class="line">    &lt;el-card&gt;</span><br><span class="line">      &lt;!-- &lt;div class&#x3D;&quot;myCharts&quot; ref&#x3D;&quot;myCharts&quot;&gt;&lt;&#x2F;div&gt; --&gt;</span><br><span class="line">      &lt;!-- 为 ECharts 准备一个具备大小（宽高）的 DOM --&gt;</span><br><span class="line">      &lt;div id&#x3D;&quot;main&quot; style&#x3D;&quot;width: 600px;height:400px;&quot;&gt;&lt;&#x2F;div&gt;</span><br><span class="line">    &lt;&#x2F;el-card&gt;</span><br><span class="line">  &lt;&#x2F;div&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import echarts from &#39;echarts&#39;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;&#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    &#x2F;&#x2F; 基于准备好的dom，初始化echarts实例</span><br><span class="line">    var myChart &#x3D; echarts.init(document.getElementById(&#39;main&#39;))</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 指定图表的配置项和数据</span><br><span class="line">    var option &#x3D; &#123;</span><br><span class="line">      title: &#123;</span><br><span class="line">        text: &#39;ECharts 入门示例&#39;</span><br><span class="line">      &#125;,</span><br><span class="line">      tooltip: &#123;&#125;,</span><br><span class="line">      legend: &#123;</span><br><span class="line">        data: [&#39;销量&#39;]</span><br><span class="line">      &#125;,</span><br><span class="line">      xAxis: &#123;</span><br><span class="line">        data: [&#39;衬衫&#39;, &#39;羊毛衫&#39;, &#39;雪纺衫&#39;, &#39;裤子&#39;, &#39;高跟鞋&#39;, &#39;袜子&#39;]</span><br><span class="line">      &#125;,</span><br><span class="line">      yAxis: &#123;&#125;,</span><br><span class="line">      series: [</span><br><span class="line">        &#123;</span><br><span class="line">          name: &#39;销量&#39;,</span><br><span class="line">          type: &#39;bar&#39;,</span><br><span class="line">          data: [5, 20, 36, 10, 10, 20]</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    &#x2F;&#x2F; 使用刚指定的配置项和数据显示图表。</span><br><span class="line">    myChart.setOption(option)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang&#x3D;&quot;less&quot; scoped&gt;</span><br><span class="line">&lt;&#x2F;style&gt;</span><br></pre></td></tr></table></figure>

<h2 id="配合获取的数据进行展示（错误的思想）"><a href="#配合获取的数据进行展示（错误的思想）" class="headerlink" title="配合获取的数据进行展示（错误的思想）"></a>配合获取的数据进行展示（错误的思想）</h2><ul>
<li>后端获取的数据如何合并到option上是一个难点</li>
<li>所以要把demo中的option删除，在data中定义一个option</li>
<li>然后再将后端的数据通过一定的方法合并到option</li>
</ul>
<h2 id="配合获取的数据进行展示（正确的思想）"><a href="#配合获取的数据进行展示（正确的思想）" class="headerlink" title="配合获取的数据进行展示（正确的思想）"></a>配合获取的数据进行展示（正确的思想）</h2><ul>
<li>在按照上面的思路进行后，发现控制台会报一个错误，所以不能这样</li>
<li>将之前data中定义的option删除</li>
<li>其实在myChart.setOption()中直接使用后端的res.data即可</li>
<li>但是达不到预期想要的效果，比如数据不会跟随鼠标而动态显示</li>
<li>因为后端返回的数据只是数据，前端还需要进行处理</li>
<li>后端还提供了一个模板，只需要将其与获取的res.data进行合并即可</li>
</ul>
<p>如何合并两个对象呢？</p>
<p>不可以使用Object.assign() 方法<code>用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。</code>因为它是浅拷贝，不能深层次的拷贝。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 意思是将a对象合并到b对象</span></span><br><span class="line"><span class="comment">// b对象数据不变，a对象的数据中假如有b不存在的，就将其拷贝过去</span></span><br><span class="line"><span class="keyword">const</span> a = &#123; <span class="attr">a</span>: <span class="number">1</span>, <span class="attr">b</span>: <span class="number">2</span> &#125;;</span><br><span class="line"><span class="keyword">const</span> b = &#123; <span class="attr">b</span>: <span class="number">1</span>, <span class="attr">c</span>: <span class="number">5</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> c=<span class="built_in">Object</span>.assign(a,b)</span><br><span class="line"><span class="built_in">console</span>.log(c) <span class="comment">// &#123; a: 1, b: 1, c: 5 &#125;</span></span><br></pre></td></tr></table></figure>

<p>所以，可以在data中定义一个数据，用来接收这两个对象的合并。这里可以使用lodash的merge函数。<br><code>cnpm install lodash -S</code><br><code>import _ from &#39;lodash&#39;</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> result = _.merge(res.data, <span class="keyword">this</span>.options)</span><br><span class="line"><span class="comment">// 使用刚指定的配置项和数据显示图表。</span></span><br><span class="line">myChart.setOption(result)</span><br></pre></td></tr></table></figure>

<h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h1><h2 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h2><h3 id="优化的策略"><a href="#优化的策略" class="headerlink" title="优化的策略"></a>优化的策略</h3><ol>
<li>生成打包的报告。从中发现并且解决问题</li>
<li>第三方库使用CDN。可以提高首屏的加载速度和效率</li>
<li>ElementUI按需加载。</li>
<li>路由懒加载。</li>
<li>首页内容定制。</li>
</ol>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/07/24/%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%883%EF%BC%89/" rel="prev" title="面试（3）">
      <i class="fa fa-chevron-left"></i> 面试（3）
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/07/31/%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%88%E6%9C%80%E7%BB%88%E7%89%88%EF%BC%89/" rel="next" title="面试最终版">
      面试最终版 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  

  </div>


          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#项目的初始化"><span class="nav-number">1.</span> <span class="nav-text">项目的初始化</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#登录退出功能"><span class="nav-number">2.</span> <span class="nav-text">登录退出功能</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#token"><span class="nav-number">2.1.</span> <span class="nav-text">token</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自动重定向路由"><span class="nav-number">2.2.</span> <span class="nav-text">自动重定向路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#less"><span class="nav-number">2.3.</span> <span class="nav-text">less</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#登录"><span class="nav-number">2.4.</span> <span class="nav-text">登录</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#axios的优化"><span class="nav-number">2.5.</span> <span class="nav-text">axios的优化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#弹框提示"><span class="nav-number">2.6.</span> <span class="nav-text">弹框提示</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#登录成功之后"><span class="nav-number">2.7.</span> <span class="nav-text">登录成功之后</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由导航守卫"><span class="nav-number">2.8.</span> <span class="nav-text">路由导航守卫</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#退出登录"><span class="nav-number">2.9.</span> <span class="nav-text">退出登录</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#elementui遇到的坑"><span class="nav-number">2.10.</span> <span class="nav-text">elementui遇到的坑</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#主页"><span class="nav-number">3.</span> <span class="nav-text">主页</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#布局"><span class="nav-number">3.1.</span> <span class="nav-text">布局</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#头部的布局"><span class="nav-number">3.2.</span> <span class="nav-text">头部的布局</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#菜单栏"><span class="nav-number">3.3.</span> <span class="nav-text">菜单栏</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#菜单栏调用API接口"><span class="nav-number">3.4.</span> <span class="nav-text">菜单栏调用API接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#为axios添加拦截器"><span class="nav-number">3.5.</span> <span class="nav-text">为axios添加拦截器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#解决菜单栏下拉时全部展开的问题"><span class="nav-number">3.6.</span> <span class="nav-text">解决菜单栏下拉时全部展开的问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#渲染二级菜单"><span class="nav-number">3.7.</span> <span class="nav-text">渲染二级菜单</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自定义icon"><span class="nav-number">3.8.</span> <span class="nav-text">自定义icon</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#UI坑"><span class="nav-number">3.9.</span> <span class="nav-text">UI坑</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#嵌套组件"><span class="nav-number">3.10.</span> <span class="nav-text">嵌套组件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#菜单栏的路由链接"><span class="nav-number">3.11.</span> <span class="nav-text">菜单栏的路由链接</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#用户列表"><span class="nav-number">4.</span> <span class="nav-text">用户列表</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#根据路由展示组件"><span class="nav-number">4.1.</span> <span class="nav-text">根据路由展示组件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#二级菜单不高亮的bug"><span class="nav-number">4.2.</span> <span class="nav-text">二级菜单不高亮的bug</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#样式的位置"><span class="nav-number">4.3.</span> <span class="nav-text">样式的位置</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#get请求带参数写法"><span class="nav-number">4.4.</span> <span class="nav-text">get请求带参数写法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数据的改造"><span class="nav-number">4.5.</span> <span class="nav-text">数据的改造</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#鼠标悬浮的提示框"><span class="nav-number">4.6.</span> <span class="nav-text">鼠标悬浮的提示框</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#使用tooltip"><span class="nav-number">4.7.</span> <span class="nav-text">使用tooltip</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#接口中有参数的解决方案"><span class="nav-number">4.8.</span> <span class="nav-text">接口中有参数的解决方案</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#搜索框的清空"><span class="nav-number">4.9.</span> <span class="nav-text">搜索框的清空</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自定义校验规则"><span class="nav-number">4.10.</span> <span class="nav-text">自定义校验规则</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#添加用户之后的bug"><span class="nav-number">4.11.</span> <span class="nav-text">添加用户之后的bug</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#修改用户数据"><span class="nav-number">5.</span> <span class="nav-text">修改用户数据</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#put请求，一个必须参数，两个非必须参数"><span class="nav-number">5.1.</span> <span class="nav-text">put请求，一个必须参数，两个非必须参数</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#删除用户数据"><span class="nav-number">6.</span> <span class="nav-text">删除用户数据</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#权限列表"><span class="nav-number">7.</span> <span class="nav-text">权限列表</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#渲染tag标签"><span class="nav-number">7.1.</span> <span class="nav-text">渲染tag标签</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#角色列表"><span class="nav-number">8.</span> <span class="nav-text">角色列表</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#表格展开操作"><span class="nav-number">8.1.</span> <span class="nav-text">表格展开操作</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#多层数据的提取"><span class="nav-number">8.2.</span> <span class="nav-text">多层数据的提取</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#角色列表展开项的美化"><span class="nav-number">8.3.</span> <span class="nav-text">角色列表展开项的美化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#标签的删除"><span class="nav-number">8.4.</span> <span class="nav-text">标签的删除</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#渲染树形数据结构"><span class="nav-number">8.5.</span> <span class="nav-text">渲染树形数据结构</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#商品分类"><span class="nav-number">9.</span> <span class="nav-text">商品分类</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#树形table"><span class="nav-number">9.1.</span> <span class="nav-text">树形table</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#上传图片功能"><span class="nav-number">10.</span> <span class="nav-text">上传图片功能</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#图片预览窗口"><span class="nav-number">11.</span> <span class="nav-text">图片预览窗口</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#富文本编辑器"><span class="nav-number">12.</span> <span class="nav-text">富文本编辑器</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#使用Echarts"><span class="nav-number">13.</span> <span class="nav-text">使用Echarts</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#基本的使用"><span class="nav-number">13.1.</span> <span class="nav-text">基本的使用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#配合获取的数据进行展示（错误的思想）"><span class="nav-number">13.2.</span> <span class="nav-text">配合获取的数据进行展示（错误的思想）</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#配合获取的数据进行展示（正确的思想）"><span class="nav-number">13.3.</span> <span class="nav-text">配合获取的数据进行展示（正确的思想）</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#结尾"><span class="nav-number">14.</span> <span class="nav-text">结尾</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#优化"><span class="nav-number">14.1.</span> <span class="nav-text">优化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#优化的策略"><span class="nav-number">14.1.1.</span> <span class="nav-text">优化的策略</span></a></li></ol></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">Edison</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">124</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">21</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">19</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
</div>
  <div class="powered-by">山高水远  一定相见
  </div>
<div></div>
<div class="theme-info">
  <div class="powered-by"></div>
  <span class="post-count">至今已写107.1k字</span>
</div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
